// 版权所有2009 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"runtime/internal/atomic"
	"runtime/internal/sys"
	"unsafe"
)

// 定义的常量
const (
	// G状态
	// 
	// 除了表示G的一般状态外，G状态
	// 就像goroutine堆栈上的锁一样（因此它的
	// 执行用户代码的能力）。
	// 
	// 如果您添加到此列表中，请将mgcmark.go中“垃圾回收期间正常”状态的
	// 添加到列表中。
	// 
	// TODO（奥斯汀）：Gscan钻头的重量可能要轻得多。例如，我们可以选择不运行运行在运行队列中找到的_gscanrunnableabcdefg
	// 直到它们成为_Grunnable。像
	// \u Gscanwaiting->\u Gscanrunnable这样的转换实际上是可以的，因为
	// /它们不会影响堆栈所有权。

	// \u Gidle表示此goroutine刚刚分配，尚未初始化。
	_Gidle = iota // 0 

	// \u Grunnable表示此goroutine位于运行队列中。它是
	// 当前未执行用户代码。该堆栈不是所有者。
	_Grunnable // 1 

	// \u Grunning意味着此goroutine可以执行用户代码。
	// 堆栈归此goroutine所有。它不在运行队列上。
	// 分配了一个M和一个P（g.M和g.M.P有效）。
	_Grunning // 2 

	// \u Gsyscall表示此goroutine正在执行系统调用。
	// 它没有执行用户代码。该堆栈属于此
	// goroutine。它不在运行队列上。它被分配了一个M.
	_Gsyscall // 3 

	// \u Gwaiting意味着此goroutine在运行时被阻止。
	// 它没有执行用户代码。它不在运行队列
	// 上，但应记录在某个位置（例如，通道等待
	// 队列），以便在必要时准备就绪（）。堆栈为
	// 非自有*除非*通道操作可以读取或
	// 写入相应通道
	// 锁下的堆栈部分。否则，在
	// goroutine进入_Gwaiting（例如，它可能会被移动）后访问堆栈是不安全的。
	_Gwaiting // 4 

	// \u Gmoribund\u unused当前未使用，但在gdb 
	// 脚本中硬编码。
	_Gmoribund_unused // 5 

	// \u Gdead表示此goroutine当前未使用。它可能是
	// 刚刚退出，在一个自由列表中，或者刚刚初始化。它
	// 未执行用户代码。它可能有也可能没有分配堆栈
	// 。G及其堆栈（如有）归退出G或从自由
	// 所有。
	// 列表获得G的M 
	_Gdead // 6 

	// \u Genqueue\u unused当前未使用。
	_Genqueue_unused // 7 

	// \u Gcopystack表示此goroutine的堆栈正在移动。它
	// 未执行用户代码，并且不在运行队列中。
	// 堆栈由放入_Gcopystack的goroutine拥有。
	_Gcopystack // 8 

	// \u Gpreempted意味着此goroutine为
	// /暂停抢占而自行停止。这就像是在等待，但没有什么比这更重要的了。某些suspendG必须CAS 
	// 等待对
	// 负责的状态为准备好（）此G。
	_Gpreempted // 9 

	// \u Gscan与上述除
	// /\u Grunning以外的状态组合表示GC正在扫描堆栈。
	// goroutine未执行用户代码，堆栈由设置_Gscan位的goroutine拥有
	// 。
	// 
	// \u Gscanrunning不同：它用于在GC发出信号让G扫描其自身的
	// 状态转换。这在其他方面就像_Grunning。
	// 堆栈时短暂阻止
	// 
	// 原子状态&~Gscan提供扫描完成时goroutine将返回的状态
	// 返回。
	_Gscan          = 0x1000
	_Gscanrunnable  = _Gscan + _Grunnable  // 0x1001 
	_Gscanrunning   = _Gscan + _Grunning   // 0x1002 
	_Gscansyscall   = _Gscan + _Gsyscall   // 0x1003 
	_Gscanwaiting   = _Gscan + _Gwaiting   // 0x1004 
	_Gscanpreempted = _Gscan + _Gpreempted // 0x1009 
)

const (
	// P状态

	// Pidle表示未使用P运行用户代码或
	// /调度程序。通常，它位于idle P列表中，对调度程序可用
	// 但它可能只是在
	// 其他国家。
	// 
	// P由空闲列表或任何
	// 正在转换其状态的对象拥有。其运行队列为空。
	_Pidle = iota

	// \u修剪意味着P归M所有，用于运行用户代码或调度程序。只有拥有此P 
	// 的M才允许将P的状态从_Prunning更改。M 
	// 可以将P转换为_Pidle（如果它没有更多的工作要做的话），_Psyscall（当输入系统调用时）或_Pgcstop（到
	// 停止GC）。M还可以将P 
	// 的所有权直接移交给另一个M（例如，安排一个锁定的g）。
	_Prunning

	// /\u Psyscall表示P没有运行用户代码。它与系统调用中的某个M具有
	// 亲和力，但不为其所有，并且
	// 可能被另一个M窃取。这与_Pidle类似，但
	// 使用轻量级转换并维护M亲和力。
	// 
	// 离开(Psyscall)必须使用CAS完成，要么窃取
	// 要么重新获取P。请注意，存在ABA危害：即使
	// M在系统调用后成功地将其原始P恢复到_修剪
	// 中，它必须理解P可能被另一个M在过渡期间使用了
	// 。
	_Psyscall

	// /_Pgcstop意味着一个P因STW而停止，并由阻止世界的M 
	// /拥有。阻止世界的M继续使用它的P，即使是在_Pgcstop。将
	// 从_Prunning转换为_Pgcstop会导致M释放其P和
	// park。
	// 
	// P保留其运行队列并启动世界将重新启动具有非空运行队列的Ps上的调度程序
	// 。
	_Pgcstop

	// /\u Pdead表示不再使用P（GOMAXPROCS收缩）。我们
	// 如果GOMAXPROCS增加，则重用Ps。一个死P大部分是
	// /被剥夺了它的资源，尽管有一些东西仍然是
	// （例如，跟踪缓冲区）。
	_Pdead
)

// 互斥锁。在无争用的情况下，
// 与自旋锁（仅几个用户级指令）一样快，但是在争用路径上，它们睡在内核中。
// 已调零的互斥锁已解锁（无需初始化每个锁）。
// 初始化有助于静态锁排序，但不是必需的。
type mutex struct {
	// 如果锁排序被禁用，则为空结构，否则包括锁排序
	lockRankStruct
	// 基于Futex的impl将其视为uint32密钥，
	// 而基于sema的impl将其视为M*waitm。
	// 以前是一个联合体，但联合体破坏了GC。
	key uintptr
}

// 在一次性事件中睡眠和醒来。
// 在调用notesleep或notewakeup之前，
// 必须调用noteclear来初始化便笺。
// 那么，只有一个线程可以调用notesleep 
// 并且只有一个线程可以调用notewakeup（一次）。
// 调用notewakeup后，notesleep 
// 将返回。未来的睡眠将立即恢复。
// 只有在
// 返回上一个notesleep后才能调用后续noteclear，例如，不允许
// 在notewakeup后直接调用noteclear。
// 
// notetsleep类似于notesleep，但在
// 给定的纳秒数后醒来，即使事件
// 尚未发生。如果一个goroutine使用notetsleep来
// 早起，它必须等待调用noteclear，直到它
// 可以确定没有其他goroutine调用
// notewakeup。
// 
// notesleep/notetsleep通常在g0上调用，
// notetsleep类似于notetsleep，但在用户g上调用。
type note struct {
	// 基于Futex的impl将其视为uint32密钥，
	// 而基于sema的impl将其视为M*waitm。
	// 过去是工会，但工会破坏了工会。
	key uintptr
}

type funcval struct {
	fn uintptr
	// 变量大小，fn特定数据此处
}

type iface struct {
	tab  *itab
	data unsafe.Pointer
}

type eface struct {
	_type *_type
	data  unsafe.Pointer
}

func efaceOf(ep *interface{}) *eface {
	return (*eface)(unsafe.Pointer(ep))
}

// guintpr、muintptr和puintptr都用于绕过写屏障。
// 当当前P已释放
// 时，避免写入障碍尤其重要，因为GC认为世界已停止，并且
// 意外写入障碍将不会与GC同步，
// 这会导致一个半执行的写屏障，该屏障标记了对象
// 但没有将其排队。如果GC跳过该对象并在
// 队列出现之前完成，它将错误地释放该对象。
// 
// 我们尝试使用特殊的赋值函数，仅当
// 持有一个正在运行的P时调用，但随后对特定内存的一些更新
// word遇到写入障碍，而有些没有。这打破了
// 写屏障阴影检查模式，而且也很可怕：让
// 一个被GC完全忽略的单词比让
// 只忽略几个更新要好。
// 
// Gs和Ps始终可以通过
// allgs和allp列表中的真指针访问，或者（在到达这些列表之前的分配过程中）
// 从堆栈变量访问。
// 
// Ms始终可以通过allm或
// freem的真指针访问。与Gs和Ps不同，我们提供免费Ms，因此
// 任何东西都不能在安全点上持有muintptr，这一点很重要。

// 一个guintpttr拥有一个goroutine指针，但输入为uintpttr 
// 以绕过写障碍。它用于Gobuf goroutine状态
// 以及在没有P.
// 
// 的情况下操作的调度列表中，Gobuf.g goroutine指针几乎总是由汇编代码更新。
// 在为数不多的几个地方之一，它是由Go代码更新的-func save-它必须是
// 作为uintptr处理，以避免在不好的时间发出写屏障。
// 我们将字段的类型更改为uintptpr，
// 程序集操作中缺少的写屏障。
// 以使其完全不需要写屏障，而不是找出如何发出
// 
// Goroutine结构在allg列表中发布，并且从未释放。
// 这将阻止收集goroutine结构。
// 从来没有一次Gobuf.g包含对goroutine的唯一引用
// 首先发布goroutine。
// Goroutine指针也保存在非GC可见的位置，如TLS、
// 所以我看不到它们一直在移动。如果我们确实想在GC中开始移动数据
// 的话，我们需要从
// 备用竞技场分配goroutine结构。使用guintptr不会让问题变得更糟。
type guintptr uintptr

// go:nosplit 
func (gp guintptr) ptr() *g { return (*g)(unsafe.Pointer(gp)) }

// go:nosplit 
func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) }

// go:nosplit 
func (gp *guintptr) cas(old, new guintptr) bool {
	return atomic.Casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new))
}

// setGNoWB执行*gp=new，无写入障碍。
// 用于无法使用guintptr的情况。
// go:nosplit-
// go:nowritebarrier-
func setGNoWB(gp **g, new *g) {
	(*guintptr)(unsafe.Pointer(gp)).set(new)
}

type puintptr uintptr

// go:nosplit-
func (pp puintptr) ptr() *p { return (*p)(unsafe.Pointer(pp)) }

// go:nosplit-
func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }

// muintptr是一个没有被垃圾收集器跟踪的*m。
// 
// 因为我们提供免费Ms，所以对
// muintptrs有一些额外的限制：
// 
// 1。切勿将muintptr固定在安全点上。中国英语学习网编译：中国英语学习网编译：中国英语学习网编译：中国英语学习网编译：中国英语学习网编译：中国英语学习网编译。堆中的任何muintptr都必须由M本身拥有，这样它就可以
// 确保在释放最后一个true*M时它没有被使用。
type muintptr uintptr

// go:nosplit 
func (mp muintptr) ptr() *m { return (*m)(unsafe.Pointer(mp)) }

// go:nosplit 
func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) }

// setMNoWB执行*mp=new，无写屏障。
// 适用于无法使用muintptr的情况。
// go:nosplit 
// go:nowritebarrier 
func setMNoWB(mp **m, new *m) {
	(*muintptr)(unsafe.Pointer(mp)).set(new)
}

type gobuf struct {
	// libmach已知sp、pc和g的偏移量（硬编码）。
	// 
	// ctxt对于GC来说是不寻常的：它可能是一个
	// 堆分配的函数，所以GC需要跟踪它，但它
	// 需要设置并从程序集中清除，因为它的
	// 很难有写障碍。然而，ctxt实际上是一个
	// 保存的实时寄存器，我们只在
	// 真实寄存器和gobuf之间交换它。因此，在堆栈扫描期间，我们将其视为
	// 根，这意味着保存
	// 并恢复它的程序集不需要写屏障。它仍然是作为指针键入的
	// 以便Go的任何其他写入操作都可以获得
	// 写入障碍。
	sp   uintptr
	pc   uintptr
	g    guintptr
	ctxt unsafe.Pointer
	ret  uintptr
	lr   uintptr
	bp   uintptr // 对于支持帧指针的体系结构
}

// sudog表示等待列表中的g，例如用于在通道上发送/接收
// 的g。
// 
// sudog是必需的，因为↔ 同步对象关系
// 是多对多。一个g可能在很多等待名单上，所以一个g可能有很多SUDOG；而且许多G可能正在等待同一个
// 同步对象，因此一个对象可能有多个sudog。
// 
// SUDOG是从一个特殊的池中分配的。使用acquireSudog和
// releaseSudog分配和释放它们。
type sudog struct {
	// 以下字段受此sudog阻塞的通道的hchan.lock保护。shrinkstack依赖于
	// 这适用于参与通道操作的sudog。

	g *g

	next *sudog
	prev *sudog
	elem unsafe.Pointer // 数据元素（可能指向堆栈）

	// 以下字段永远不会同时访问。
	// 对于通道，waitlink仅由g访问。
	// 对于信号量，所有字段（包括上面的字段）
	// 仅在持有信号根锁时才可访问。

	acquiretime int64
	releasetime int64
	ticket      uint32

	// isSelect表示g正在参加select，因此
	// g.selectDone必须在唤醒比赛中获胜。
	isSelect bool

	// 成功表示通过通道c的通信是否成功。如果goroutine被唤醒是因为通过通道c传递了
	// 值，则为true；如果被唤醒是因为c被关闭，则为false。
	success bool

	parent   *sudog // semaRoot二叉树
	waitlink *sudog // g.waiting list或semaRoot 
	waittail *sudog // semaRoot 
	c        *hchan // channel 
}

type libcall struct {
	fn   uintptr
	n    uintptr // 参数数
	args uintptr // 参数
	r1   uintptr // 返回值
	r2   uintptr
	err  uintptr // 错误数
}

// 堆栈描述一个Go执行堆栈。
// 堆栈的边界完全是[lo，hi]，
// 两侧没有隐式数据结构。
type stack struct {
	lo uintptr
	hi uintptr
}

// heldLockInfo提供了关于持有锁的信息以及该锁的级别
type heldLockInfo struct {
	lockAddr uintptr
	rank     lockRank
}

type g struct {
	// 堆栈参数。
	// 堆栈描述了实际的堆栈内存：[stack.lo，stack.hi）.
	// stackguard0是在Go stack growth序言中比较的堆栈指针.
	// 通常是stack.lo+StackGuard，但可以通过StackPreempt触发抢占.
	// stackguard1是在C stack growth序言中比较的堆栈指针.
	// 是g0和gsignal堆栈上的stack.lo+StackGuard.
	// 在其他goroutine堆栈上为~0，以触发对morestackc的调用（并崩溃）.
	stack       stack   // 运行时已知偏移量/cgo 
	stackguard0 uintptr // liblink已知偏移量
	stackguard1 uintptr // liblink已知偏移量

	_panic    *_panic // 最内层恐慌-liblink已知偏移量
	_defer    *_defer // 最内层延迟
	m         *m      // 当前m；arm liblink已知偏移量
	sched     gobuf
	syscallsp uintptr // 如果status==Gsyscall，syscallsp=sched.sp在gc期间使用
	syscallpc uintptr // 如果status==Gsyscall，syscallpc=sched.pc在gc期间使用
	stktopsp  uintptr // 堆栈顶部的预期sp，以检查回溯
	// param是一个通用指针参数字段，用于在其他用于e 
	// 参数将很难找到。目前使用
	// 有三种方式：
	// 1.当通道操作唤醒阻塞的goroutine时，它将param设置为
	// 指向已完成阻塞操作的sudog。
	// 2.通过gcAssistAlloc1来签名l返回给调用方goroutine完成了
	// GC循环。以任何其他方式这样做都是不安全的，因为goroutine的
	// 堆栈在此期间可能已移动。
	// 3.通过debugCallWrap将参数传递给新的goroutine，因为分配了
	// 闭包在运行时是禁止的。
	param        unsafe.Pointer
	atomicstatus uint32
	stackLock    uint32 // sigprof/scang lock；TODO:折叠到原子状态
	goid         int64
	schedlink    guintptr
	waitsince    int64      // g被阻止的大约时间
	waitreason   waitReason // 如果状态==Gwaiting 

	preempt       bool // 抢占信号，复制stackguard0=stackpreempt 
	preemptStop   bool // 转换到抢占时释放的GPU；其他或者，只需取消调度
	preemptShrink bool // 在同步安全点收缩堆栈

	// 如果g在异步
	// 安全点停止，则设置异步安全点。这意味着堆栈上有帧
	// 没有精确的指针信息。
	asyncSafePoint bool

	paniconfault bool // 死机（而不是崩溃）在意外故障地址
	gcscandone   bool // g已扫描堆栈；受状态
	throwsplit   bool // 中的_Gscan位保护
	// activeStackChans表示有未锁定的通道
	// 指向此goroutine的堆栈。如果为true，则堆栈
	// 需要复制到acquire通道锁用于保护堆栈中的这些区域。
	// 驻车Onchan表示goroutine即将驻车在chansend或chanrecv上。用于向不安全点发送信号
	activeStackChans bool
	// 用于堆叠收缩。它是一个布尔值，但会自动更新。
	parkingOnChan uint8

	raceignore     int8     // 忽略种族检测事件
	sysblocktraced bool     // StartTrace已发出有关此goroutine的EVGOINSCALL 
	tracking       bool     // 我们是否跟踪此G以获取sched延迟统计
	trackingSeq    uint8    // 用于决定是否跟踪此G 
	runnableStamp  int64    // G上次可运行的时间戳，仅用于跟踪
	runnableTime   int64    // 可运行、运行时清除的时间量，仅用于跟踪
	sysexitticks   int64    // 返回syscall时的cputicks（用于跟踪）
	traceseq       uint64   // 跟踪事件序列器
	tracelastp     puintptr // 最后一个P为此goroutine发出了一个事件
	lockedm        muintptr
	sig            uint32
	writebuf       []byte
	sigcode0       uintptr
	sigcode1       uintptr
	sigpc          uintptr
	gopc           uintptr         // 创建此goroutine的pc of go语句
	ancestors      *[]ancestorInfo // 创建此goroutine的goroutine的祖先信息（仅在debug.traceback祖先时使用）
	startpc        uintptr         // goroutine函数的pc 
	racectx        uintptr
	waiting        *sudog         // /sudog正在等待的结构（具有有效的元素ptr）；按锁定顺序
	cgoCtxt        []uintptr      // cgo回溯上下文
	labels         unsafe.Pointer // 探查器标签
	timer          *timer         // 缓存时间计时器。睡眠
	selectDone     uint32         // 我们是否参加了选择赛，是否有人赢得了比赛？

	// Per-G GC state 

	// gcAssistBytes就分配的
	// 字节而言，这是G的GC辅助积分。如果这是肯定的，则G有权在没有协助的情况下分配gcAssistBytes字节。如果此
	// 为负值，则G必须通过执行
	// 扫描工作来纠正此错误。我们以字节为单位跟踪它，以便快速更新
	// 并检查malloc热路径中的债务。辅助比率
	// 确定这与扫描工作债务的对应关系。
	gcAssistBytes int64
}

// gTrackingPeriod是两次
// 延迟跟踪运行之间的转换次数。
const gTrackingPeriod = 8

const (
	// tlsSlots是在某些平台上为TLS保留的指针大小的插槽数，如Windows。
	tlsSlots = 6
	tlsSize  = tlsSlots * sys.PtrSize
)

type m struct {
	g0      *g     // goroutine with scheduling stack 
	morebuf gobuf  // gobuf arg to morestack 
	divmod  uint32 // div/mod arm分母-liblink已知

	// 调试器未知字段。
	procid        uint64            // 用于调试器，但偏移量未硬编码
	gsignal       *g                // 信号处理g 
	goSigStack    gsignalStack      // Go分配的信号处理堆栈
	sigmask       sigset            // 用于保存的信号掩码的存储
	tls           [tlsSlots]uintptr // 线程本地存储（用于x86外部寄存器）
	mstartfn      func()
	curg          *g       // 当前正在运行的goroutine 
	caughtsig     guintptr // goroutine在致命信号
	p             puintptr // 用于执行go代码的附加p（如果不执行go代码，则为零）
	nextp         puintptr
	oldp          puintptr // 在执行系统调用之前附加的p 
	id            int64
	mallocing     int32
	throwing      int32
	preemptoff    string // 如果！=“”，保持curg在此m上运行
	locks         int32
	dying         int32
	profilehz     int32
	spinning      bool // m已停止工作并正在积极寻找工作
	blocked       bool // m被阻止在便笺
	newSigstack   bool // minit在名为sigaltstack的C线程上
	printlock     int8
	incgo         bool   // m正在执行cgo调用
	freeWait      uint32 // if==0，可以安全地释放g0并删除m（原子）
	fastrand      [2]uint32
	needextram    bool
	traceback     uint8
	ncgocall      uint64      // 总cgo调用数
	ncgo          int32       // 当前正在进行的cgo调用数
	cgoCallersUse uint32      // 如果非零，暂时使用的cgo调用程序
	cgoCallers    *cgoCallers // cgo调用中崩溃时的cgo回溯
	doesPark      bool        // 非P运行线程：sysmon和newmHandoff从不使用。在创建此线程的所有M 
	park          note
	alllink       *m // 。
	schedlink     muintptr
	lockedg       guintptr
	createstack   [32]uintptr // 堆栈上驻车
	lockedExt     uint32      // 跟踪外部锁线程
	lockedInt     uint32      // 跟踪内部锁线程
	nextwaitm     muintptr    // 下一个m等待锁
	waitunlockf   func(*g, unsafe.Pointer) bool
	waitlock      unsafe.Pointer
	waittraceev   byte
	waittraceskip int
	startingtrace bool
	syscalltick   uint32
	freelink      *m // 在sched.freem 

	// mFixup用于同步操作系统相关的m状态
	// （凭据等）使用互斥访问。为了避免死锁
	// 在mDoFixupFn（）
	// 中使用的原子.Load（）为零保证fn为零。
	mFixup struct {
		lock mutex
		used uint32
		fn   func(bool) bool
	}

	// 之所以出现这些函数，是因为它们太大，无法放在低级别NOSPLIT函数的堆栈上。
	libcall   libcall
	libcallpc uintptr // 对于cpu探查器
	libcallsp uintptr
	libcallg  guintptr
	syscall   libcall // 在windows上存储系统调用参数

	vdsoSP uintptr // 在VDSO调用时用于回溯的SP（如果不在调用中则为0）
	vdsoPC uintptr // 在VDSO调用时用于回溯的PC 

	// 抢占根统计完成的抢占
	// 信号数。这用于检测何时请求抢占
	// 但失败。以原子方式访问。
	preemptGen uint32

	// 这是否是此M上的挂起抢占信号。
	// 以原子方式访问。
	signalPending uint32

	dlogPerM

	mOS

	// 此m最多持有10个锁，由锁排序代码维护。
	locksHeldLen int
	locksHeld    [10]heldLockInfo
}

type p struct {
	id          int32
	status      uint32 // 皮德尔/修剪/之一。。。
	link        puintptr
	schedtick   uint32     // 每次调度程序调用递增
	syscalltick uint32     // 每次系统调用递增
	sysmontick  sysmontick // 系统监视到的最后一个勾号
	m           muintptr   // 反向链接到关联的m（如果空闲则为零）
	mcache      *mcache
	pcache      pageCache
	raceprocctx uintptr

	deferpool    [5][]*_defer // 不同大小的可用延迟结构池（请参阅panic.go）
	deferpoolbuf [5][32]*_defer

	// goroutine id的缓存，摊销对runtime·sched.goidgen的访问。
	goidcache    uint64
	goidcacheend uint64

	// 可运行goroutine的队列。无锁访问。
	runqhead uint32
	runqtail uint32
	runq     [256]guintptr
	// runnext，如果非零，则是由
	// 当前G准备好的可运行G，应该在下一个运行，而不是
	// 如果运行G的时间还有时间，则运行Q 
	// 切片。它将继承当前时间
	// 切片中剩余的时间。如果一组goroutine被锁定在
	// 通信和等待模式中，则这将调度设置为
	// 单元的goroutine，并消除将准备好的
	// goroutine添加到运行队列末尾时产生的（可能较大的）调度延迟。
	// 
	// 注意，虽然其他P可能会自动将其归零，但
	// 只有所有者P可以将其归零为有效的G。
	runnext guintptr

	// 可用G（status==Gdead）
	gFree struct {
		gList
		n int32
	}

	sudogcache []*sudog
	sudogbuf   [128]*sudog

	// 堆中mspan对象的缓存。
	mspancache struct {
		// 我们需要一个显式长度，因为这个字段在不允许写屏障的分配代码路径中使用
		// 并且消除写屏障/保持从
		// 切片更新中消除写屏障是很棘手的，不仅仅是管理长度
		// 我们自己。
		len int
		buf [128]*mspan
	}

	tracebuf traceBufPtr

	// traceSweep表示应跟踪扫描事件。
	// 用于延迟扫描开始事件，直到实际扫描完跨度
	// 为止。
	traceSweep bool
	// traceSwept和tracerclaimmed跟踪当前扫描循环中通过扫描扫描扫描和回收的字节数。
	traceSwept, traceReclaimed uintptr

	palloc persistentAlloc // per-P以避免互斥

	_ uint32 // 对齐位于

	// 计时器堆上第一个条目的when字段下面的原子字段。
	// 这是使用原子函数更新的。
	// 如果计时器堆为空，则为0。
	timer0When uint64

	// 具有
	// TIMERMODIFIEDEARLYER状态的计时器的已知最早的nextwhen字段。由于计时器可能已被
	// 再次修改，因此不需要任何具有此值的计时器。
	// 这是使用原子函数更新的。
	// 如果没有时间修改的早期计时器，则为0。
	timerModifiedEarliest uint64

	// Per-P GC状态
	gcAssistTime         int64 // assistAlloc中的纳秒
	gcFractionalMarkTime int64 // 分数标记工作程序（原子）中的纳秒

	// gcMarkWorkerMode是下一个标记工作程序运行的模式。
	// 也就是说，它用于与工作进程goroutine通信
	// 由
	// gcController.findrunablegcworker选择立即执行。在调度其他goroutine时，
	// 此字段必须设置为gcMarkWorkerNotWorker。
	gcMarkWorkerMode gcMarkWorkerMode
	// gcMarkWorkerStartTime是最近的
	// mark worker启动的nanotime（）。
	gcMarkWorkerStartTime int64

	// gcw是P的GC工作缓冲缓存。工作缓冲区是
	// 由写屏障填充，由mutator assists耗尽，
	// 在某些GC状态转换上处理。
	gcw gcWork

	// wbBuf是这个P的GC写屏障缓冲区。ABCFDG 
	wbBuf wbBuf


	statsSeq uint32

	// 定时器锁。我们通常在这个P上运行
	// 时访问计时器，但调度程序也可以从另一个P进行访问。
	timersLock mutex

	// 在某个时间要执行的操作。用于实现
	// 标准库的时间包。
	// 必须持有timersLock才能访问。
	timers []*timer

	// P堆中的计时器数。
	// 使用原子指令修改。
	numTimers uint32

	// P堆中已删除计时器的数量。
	// 使用原子指令修改。
	deletedTimers uint32

	// 执行计时器函数时使用的竞争上下文。
	timerRaceCtx uintptr

	// preempt设置为指示此P应尽快进入
	// 调度程序（无论G在其上运行什么）。
	preempt bool

	// 不再需要填充。错误共享现在不成问题，因为p足够大
	// 其大小类是缓存线大小的整数倍（对于我们的任何体系结构）。
}

type schedt struct {
	// 以原子方式访问。保持在顶部，以确保在32位系统上对齐。
	goidgen   uint64
	lastpoll  uint64 // 最后一次网络轮询的时间，如果当前正在轮询，则为0 
	pollUntil uint64 // 当前轮询睡眠的时间

	lock mutex

	// 增加nmidle、NMIDELOCKED、nmsys或nmfreed时，请确保调用checkdead（）。

	midle        muintptr // 空闲m等待工作
	nmidle       int32    // 空闲m等待工作的数量
	nmidlelocked int32    // 锁定m等待工作的数量
	mnext        int64    // 已创建和下一个m ID 
	maxmcount    int32    // 允许的最大m数量（或死亡）
	nmsys        int32    // 死锁未统计的系统m数
	nmfreed      int64    // 已释放的m的累计数

	ngsys uint32 // 系统goroutine数；更新了原子

	pidle      puintptr // idle p的
	npidle     uint32
	nmspinning uint32 // 请参阅proc.go中的“工作线程停止/取消连接”注释。

	// 全局可运行队列。
	runq     gQueue
	runqsize int32

	// 禁用控制程序的选择性禁用。
	// 
	// 使用schedEnableUser控制此操作。
	// 
	// 禁用受sched.lock保护。
	disable struct {
		// 用户禁用用户goroutine的调度。
		user     bool
		runnable gQueue // 挂起的可运行Gs 
		n        int32  // 可运行的长度
	}

	// 死G的全局缓存。
	gFree struct {
		lock    mutex
		stack   gList // Gs带堆栈
		noStack gList // Gs不带堆栈
		n       int32
	}

	// sudog结构的中央缓存。
	sudoglock  mutex
	sudogcache *sudog

	// 不同大小的可用延迟结构的中心池。
	deferlock mutex
	deferpool [5]*_defer

	// freem是设置了
	// m.exited后等待释放的m的列表。通过m.freelink链接。
	freem *m

	gcwaiting  uint32 // gc正在等待运行
	stopwait   int32
	stopnote   note
	sysmonwait uint32
	sysmonnote note

	// 如果为true，则sysmon未准备好进行mFixup调用。
	// 以原子方式访问。
	sysmonStarting uint32

	// 如果设置了P.runSafePointFn，则应在下一个GC对每个P调用safepointFn。
	safePointFn   func(*p)
	safePointWait int32
	safePointNote note

	profilehz int32 // cpu评测率

	procresizetime int64 // /nanotime（）对gomaxprocs的最后更改
	totaltime      int64 // ∫gomaxprocs dt直到procresizetime 

	// sysmonlock在运行时保护sysmon的操作。
	// 
	// 获取并保持此互斥锁，以阻止sysmon与其余运行时交互
	// 。
	sysmonlock mutex

	_ uint32 // 确保timeToRun具有8字节对齐

	// timeToRun是调度延迟的分布，定义为
	// 在
	// 转换为_Grunning之前G处于_Grunnable状态的时间总和。
	// 
	// timeToRun受sched.lock保护。
	timeToRun timeHistogram
}

// SIGTAB的标志字段的值。
const (
	_SigNotify   = 1 << iota // let signal.Notify have signal，即使来自内核
	_SigKill                 // if signal.Notify不接受它，悄悄退出
	_SigThrow                // if signal.Notify不接受它，大声退出
	_SigPanic                // 如果信号来自内核，如果没有明确请求信号，则惊慌
	_SigDefault              // ，不要监视它
	_SigGoExit               // 导致所有运行时进程退出（仅用于计划9）。
	_SigSetStack             // 将sau ONSTACK添加到libc处理程序
	_SigUnblock              // 始终取消阻止；参见blockableSig 
	_SigIgn                  // /\u SIG\u DFL操作是忽略信号
)

// 内存中每个函数的布局由链接器
// 参见https:
// 与链接器（../cmd/link/internal/ld/pcln.go:/pclntab）保持同步
// 并与包运行时中的包调试/gosym和symtab.go保持同步。
type _func struct {
	entry   uintptr // 启动pc 
	nameoff int32   // 函数名

	args        int32  // 输入/输出参数大小
	deferreturn uint32 // 延迟返回调用指令从条目开始的偏移量（如果有）。

	pcsp      uint32
	pcfile    uint32
	pcln      uint32
	npcdata   uint32
	cuOffset  uint32 // 此函数的CU 
	funcID    funcID // 为某些特殊运行时函数设置的runtime.cutab偏移量
	flag      funcFlag
	_         [1]byte // pad 
	nfuncdata uint8   // 必须是最后一个，必须在uint32对齐边界上结束
}

// 为内联代码中出现的PC返回的伪函数。
// A*Func可以是A*u Func或A*funcil，它们由第一个UINTPTTR区分为
// 。
type funcinl struct {
	zero  uintptr // 设置为0以区别于实帧（最外层）的_func
	entry uintptr // 条目。
	name  string
	file  string
	line  int
}

// 编译器已知的Itab布局
// 分配到非垃圾收集内存
// 需要与
// ^func.WriteTabs同步。
type itab struct {
	inter *interfacetype
	_type *_type
	hash  uint32 // 复制_type.hash。用于类型开关。
	_     [4]byte
	fun   [1]uintptr // 可变大小。fun[0]==0表示_type不实现inter。
}

// 无锁堆栈节点。
// 也被称为export_test.go。
type lfnode struct {
	next    uint64
	pushcnt uintptr
}

type forcegcstate struct {
	lock mutex
	g    *g
	idle uint32
}

// extendRandom将r[：n]中的随机数扩展到整个切片r。
// 将n<0视为n==0。
func extendRandom(r []byte, n int) {
	if n < 0 {
		n = 0
	}
	for n < len(r) {
		// 使用哈希函数和时间种子扩展随机位
		w := n
		if w > 16 {
			w = 16
		}
		h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w))
		for i := 0; i < sys.PtrSize && n < len(r); i++ {
			r[n] = byte(h)
			n++
			h >>= 8
		}
	}
}

// 延迟在延迟调用列表中保留一个条目。
// 如果在此处添加字段，请添加代码以在freedefer和deferProcStack中清除它
// 此结构必须与cmd/compile/internal/reflectdata/reflect.go:deferstruct 
// 和cmd/compile/internal/gc/ssa.go:（*state）.调用中的代码相匹配。
// 将在堆栈上分配一些延迟，在堆上分配一些延迟。
// 所有延迟在逻辑上都是堆栈的一部分，因此不需要为
// 初始化它们。必须手动扫描所有延迟，
// 对于堆延迟，标记。
type _defer struct {
	siz     int32 // 包括参数和结果
	started bool
	heap    bool
	// openDefer表示此_defer用于带有开放编码
	// defers的帧。对于整个帧，我们只有一个延迟记录（这可能是
	// 当前有0个、1个或多个延迟处于活动状态）。
	openDefer bool
	sp        uintptr  // 延迟时的sp 
	pc        uintptr  // 延迟时的pc 
	fn        *funcval // 对于开放编码延迟可以为零
	_panic    *_panic  // 正在运行延迟
	link      *_defer

	// 如果openDefer为真，下面的字段记录有关堆栈
	// 帧和具有开放编码延迟的关联函数的值。sp 
	// 以上将是帧的sp，pc将是函数中
	// 返回调用的地址。
	fd   unsafe.Pointer // funcdata用于与帧关联的函数
	varp uintptr        // 堆栈帧的varp值
	// framepc是与堆栈帧关联的当前pc。
	// 加上上面的sp（与堆栈帧关联的sp），
	// framepc/sp可以作为pc/sp对，通过
	// gentraceback（）继续堆栈跟踪。
	framepc uintptr
}

// A panic保存有关活跃恐慌的信息。
// 
// A _panic值只能存在于堆栈上。
// 
// argp和link字段是堆栈指针，但在堆栈增长期间不需要特殊的
// 处理：因为它们是指针类型的，并且
// /\临时值只存在于堆栈上，常规堆栈指针
// 调整会处理它们。
type _panic struct {
	argp      unsafe.Pointer // 指向死机期间延迟调用运行的参数的指针；无法移动-已知liblink 
	arg       interface{}    // 参数到panic 
	link      *_panic        // 链接到早期的panic 
	pc        uintptr        // 如果绕过此panic，在运行时返回到哪里
	sp        unsafe.Pointer // 如果绕过此panic，在运行时返回到哪里死机被中止
	goexit    bool
}

// 堆栈跟踪
type stkframe struct {
	fn       funcInfo   // 正在运行的函数
	pc       uintptr    // fn内的程序计数器
	continpc uintptr    // 可以继续执行的程序计数器，或者0如果不是
	lr       uintptr    // 调用者的程序计数器aka链接寄存器
	sp       uintptr    // pc的堆栈指针
	fp       uintptr    // 调用者的堆栈指针aka帧指针
	varp     uintptr    // 局部变量的顶部
	argp     uintptr    // 函数参数的指针
	arglen   uintptr    // argp 
	argmap   *bitvector // 强制使用此argmap 
}

// ancestorInfo记录goroutine启动位置的详细信息。
type ancestorInfo struct {
	pcs  []uintptr // 此goroutine堆栈中的PC 
	goid int64     // 此goroutine的goroutine id；原始goroutine可能已死亡
	gopc uintptr   // 创建此goroutine 
}

const (
	_TraceRuntimeFrames = 1 << iota // 的pc of go语句包含内部运行时函数的帧。
	_TraceTrap                      // 初始PC、SP来自陷阱，而不是调用返回的PC 
	_TraceJumpStack                 // 如果回溯在系统堆栈上，则在调用它的g处恢复跟踪
)

// 回溯打印的最大帧数
const _TracebackMaxFrames = 100

// 等待原因解释了goroutine被停止的原因。
// 见戈帕克。不要重复使用等待原因，添加新的原因。
type waitReason uint8

const (
	waitReasonZero                  waitReason = iota // “
	waitReasonGCAssistMarking                         // ”GC辅助标记“
	waitReasonIOWait                                  // /“IO等待”
	waitReasonChanReceiveNilChan                      // /“chan接收（无chan）”
	waitReasonChanSendNilChan                         // /“chan发送（无chan）”
	waitReasonPanicWait                               // /“恐慌等待”
	waitReasonSelect                                  // /“选择”
	waitReasonSelectNoCases                           // /“选择（无案例）”
	waitReasonGCAssistWait                            // /“GC辅助等待”
	waitReasonGCSweepWait                             // /“GC扫描等待”
	waitReasonGCScavengeWait                          // /“GC清除等待”
	waitReasonChanReceive                             // /“chan接收”
	waitReasonChanSend                                // /“chan发送”
	waitReasonFinalizerWait                           // /“终结器等待”
	waitReasonForceGCIdle                             // /“强制GC（空闲）”
	waitReasonSemacquire                              // /“semacquire”
	waitReasonSyncCondWait                            // /“sync.Cond.Wait”
	waitReasonTimerGoroutineIdle                      // /“timer goroutine（idle）”
	waitReasonTraceReaderBlocked                      // /“trace reader（blocked）”
	waitReasonWaitForGCCycle                          // /“Wait for GC cycle”
	waitReasonGCWorkerIdle                            // /“GC worker（idle）”
	waitReasonPreempted                               // /“preempted”
	waitReasonDebugCall                               // /“debug call”
)

var waitReasonStrings = [...]string{
	waitReasonZero:                  "",
	waitReasonGCAssistMarking:       "GC assist marking",
	waitReasonIOWait:                "IO wait",
	waitReasonChanReceiveNilChan:    "chan receive (nil chan)",
	waitReasonChanSendNilChan:       "chan send (nil chan)",
	waitReasonDumpingHeap:           "dumping heap",
	waitReasonGarbageCollection:     "garbage collection",
	waitReasonGarbageCollectionScan: "garbage collection scan",
	waitReasonPanicWait:             "panicwait",
	waitReasonSelect:                "select",
	waitReasonSelectNoCases:         "select (no cases)",
	waitReasonGCAssistWait:          "GC assist wait",
	waitReasonGCSweepWait:           "GC sweep wait",
	waitReasonGCScavengeWait:        "GC scavenge wait",
	waitReasonChanReceive:           "chan receive",
	waitReasonChanSend:              "chan send",
	waitReasonFinalizerWait:         "finalizer wait",
	waitReasonForceGCIdle:           "force gc (idle)",
	waitReasonSemacquire:            "semacquire",
	waitReasonSleep:                 "sleep",
	waitReasonSyncCondWait:          "sync.Cond.Wait",
	waitReasonTimerGoroutineIdle:    "timer goroutine (idle)",
	waitReasonTraceReaderBlocked:    "trace reader (blocked)",
	waitReasonWaitForGCCycle:        "wait for GC cycle",
	waitReasonGCWorkerIdle:          "GC worker (idle)",
	waitReasonPreempted:             "preempted",
	waitReasonDebugCall:             "debug call",
}

func (w waitReason) String() string {
	if w < 0 || w >= waitReason(len(waitReasonStrings)) {
		return "unknown wait reason"
	}
	return waitReasonStrings[w]
}

var (
	allm       *m
	gomaxprocs int32
	ncpu       int32
	forcegc    forcegcstate
	sched      schedt
	newprocs   int32

	// allpLock保护allp、IDLEPSMASK、
	// 和TIMERPSMASK的无P读取和大小更改，以及对allp的所有写入。
	allpLock mutex
	// len（allp）=gomaxprocs；可能在安全点更改，否则
	// 不可变。
	allp []*p
	// Pidle list中Ps的位掩码，每P一位。读取和写入必须
	// 是原子的。长度可能在安全点发生变化。
	// 
	// 每个P只能更新自己的位。为了保持
	// 一致性，处于空闲状态的P必须与
	// 同时更新sched.lock下的空闲P列表，否则赛车
	// pidleget可能会在pidleput设置掩码之前清除掩码，
	// 损坏位图。
	// 
	// N.B.，Procuresize拥有Stop the World with Sema中所有Ps的所有权。
	idlepMask pMask
	// 可能有计时器的Ps的位掩码，每P一位。读写
	// 必须是原子的。长度可能在安全点发生变化。
	timerpMask pMask

	// GC停放的后台工作人员池。条目类型为
	// /*gcBgMarkWorkerNode。
	gcBgMarkWorkerPool lfstack

	// gcBgMarkWorker goroutine的总数。受worldsema保护。
	gcBgMarkWorkerCount int32

	// 有关可用cpu功能的信息。
	// 运行时之外的包不应使用这些
	// 因为它们不是外部api。
	// 在asm{386，amd64}中启动时设置。
	processorVersionInfo uint32
	isIntel              bool
	lfenceBeforeRdtsc    bool

	goarm uint8 // 由arm系统上的cmd/link设置
)

// 由链接器设置，以便运行时可以确定构建模式。
var (
	islibrary bool // /-buildmode=c-shared 
	isarchive bool // /-buildmode=c-archive 
)

// 必须与内部/buildcfg.experience.FramePointer一致。
const framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64"
